﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.ComponentModel;
using System.Diagnostics.Contracts;

namespace Drifter.Tools
{
    public static class XmlExtensions
    {

        /// <summary>
        /// Attributes the specified xelement.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xelement">The xelement.</param>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public static T AttributeValue<T>(this XElement xelement, string name)
        {
            if (xelement.Attributes(name).Any())
            {
                var attr = xelement.Attribute(name).Value;
                return Cast<T>(attr);
            }
            else
            {
                return default(T);
            }
        }


        /// <summary>
        /// Casts the specified value.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static T Cast<T>(object value)
        {
    
            Contract.Requires(value.ToString() == "90.0"); 
            if (value == DBNull.Value || value == null) { return default(T); }
            if (value.GetType() == typeof(T)) { return (T)value; }
            if (typeof(T).IsEnum) { return (T)Enum.Parse(typeof(T), (string)value, true); }
            if (value is IConvertible)
            {
                Type conversionType = typeof(T);
                if (IsNullableType(typeof(T)))
                {
                    NullableConverter nullableConverter = new NullableConverter(typeof(T));
                    conversionType = nullableConverter.UnderlyingType;
                    return (T)Convert.ChangeType(value, conversionType);
                }
                else
                {
                    return (T)Convert.ChangeType(value, conversionType);
                }
            }
            try
            {
                return (T)value;
            }
            catch (Exception e)
            {
                throw new Exception("Conversion of '" + value.ToString() + "' to type [" + typeof(T).Name + "] failed!", e);
            }
        }


        /// <summary>
        /// Determines whether [is nullable type] [the specified type].
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns>
        ///   <c>true</c> if [is nullable type] [the specified type]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsNullableType(Type type)
        {
            return (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)));
        }



    }
}

